package fons.navigator.ui.browsers.dimensions;

import java.awt.Color;
import java.awt.geom.Point2D;

import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolox.util.PFixedWidthStroke;
import fons.navigator.util.piccolo.PNodes;

public class Connections {

	public static Connection removableFlexibleConnection (final Block a, final Block b, Runnable onRemove) {
		return removableConnection(a, b, true, onRemove);
	}

	public static Connection removableFixedConnection (final Block a, final Block b, Runnable onRemove) {
		return removableConnection(a, b, false, onRemove);
	}

	public static Connection removableConnection (final Block a, final Block b, boolean flexible, final Runnable onRemove) {
		if (a.isConnectedTo(b)) return a.getConnectionTo(b);
		final Connection c = newConnection(a, b, flexible);

		c.getMenu().add("Entfernen", new Runnable() {
			@Override
			public void run() {
				c.disjoin();
				a.removeConnection(c);
				b.removeConnection(c);
				a.getCanvas().removeConnection(c);
				onRemove.run();
			}
		});

		return c;
	}

	public static Connection fixedConnection (Block a, Block b) {
		return newConnection(a, b, false);
	}

	public static Connection flexibleConnection (Block a, Block b) {
		return newConnection(a, b, true);
	}

	public static Connection newConnection (Block a, Block b, boolean flexible) {
		if (a.isConnectedTo(b)) return a.getConnectionTo(b);

		final Connection c = new Connection(a.getCanvas(), a, b, flexible);
		a.addConnection(c);
		b.addConnection(c);
		c.rejoin();
		return c;
	}
	
	public static void removeConnection (Connection c) {
		if (c != null) {
			c.disjoin();
			c.getSource().removeConnection(c);
			c.getTarget().removeConnection(c);
		}
	}

	public static void removeConnection (Block a, Block b) {
		removeConnection(a.getConnectionTo(b));		
	}

	public static void createManualConnection (final Block startingBlock) {
		final PPath line = new PPath();
		final DimensionBrowserCanvas canvas = startingBlock.getCanvas();

		line.setStroke(new PFixedWidthStroke(2));
		line.setStrokePaint(Color.GRAY);
		canvas.getLayer().addChild(line);
		line.moveToBack();

		canvas.addInputEventListener(new PBasicInputEventHandler() {
			private void lineTo(final Point2D target) {
				final Point2D p = startingBlock.getGlobalBounds().getCenter2D();
				line.reset();
				line.moveTo((float) p.getX(), (float) p.getY());
				line.lineTo((float) target.getX(), (float) target.getY());
			}

			private Block lastBlock;
			private ConnectionMenu menu;

			@Override
			public void mouseMoved(PInputEvent event) {
				super.mouseMoved(event);

				if (menu == null || !menu.isShown()) {
					if (lastBlock != null && !lastBlock.getGlobalBounds().contains(event.getPosition())) {
						lastBlock.setHighlighted(false);
						lineTo(event.getPosition());

					} else if (lastBlock != null) {
						lineTo(lastBlock.getGlobalBounds().getCenter2D());

					} else {
						lineTo(event.getPosition());
					}
				}
			}

			@Override
			public void mouseEntered(PInputEvent event) {
				if (menu == null || !menu.isShown()) {
					Block b = PNodes.getAncestorOfType(event.getPickedNode(), Block.class);
					if (b != null && b != startingBlock && b != lastBlock) {
						lastBlock = b;
						menu = new ConnectionMenu(canvas.getCamera(), startingBlock, lastBlock, 
								new Runnable() {
							@Override
							public void run() {
								abort();
							}
						});
						menu.add("Abbrechen");
						startingBlock.modifyConnectionMenu(menu);
						b.setHighlighted(true);
					}
				}
			}


			@Override
			public void mouseClicked(PInputEvent event) {
				super.mouseClicked(event);

				if (lastBlock != null && lastBlock != startingBlock
						&& lastBlock.getGlobalBounds().contains(event.getPosition())) {
					menu.showAtView(event.getPosition(), lastBlock);
				}
			}

			@Override
			public void keyboardFocusLost(PInputEvent event) {
				abort();
			}

			private void abort () {
				if (lastBlock != null) {
					lastBlock.setHighlighted(false);
				}
				canvas.getLayer().removeChild(line);
				canvas.removeInputEventListener(this);
			}

		});

	}	
}
